home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
ACORNUSERS
/
EMULATOR
/
MAGICKIT
/
assembler
/
c
/
expr
< prev
next >
Wrap
Text File
|
1998-04-14
|
7KB
|
425 lines
#include <stdio.h>
#include <ctype.h>
#include "defs.h"
#include "externs.h"
int push_val(int *ip);
char check_keyword(void);
int push_op(char op);
int op_pri(char op);
int do_op(void);
char *keyword[4] = { "\4HIGH", "\3LOW", "\4PAGE", "\4BANK"};
unsigned char op_stack[64] = { '' };
unsigned long val_stack[64];
struct t_symbol *vlablptr;
int op_idx, val_idx;
int vcount;
int vflag;
/* evaluate expression */
evaluate(int *ip, char flag)
{
int end, level;
unsigned char c;
end = 0;
vflag = 0;
level = 0;
undef = 0;
op_idx = 0;
val_idx = 0;
value = 0;
val_stack[0] = 0;
while (!end) {
c = prlnbuf[*ip];
if (isalnum(c) || c == '_' || c == '.') {
if (vflag == 1)
goto error;
if (!push_val(ip))
return (0);
}
else {
switch (c) {
case '$':
case '\'':
if (vflag == 1)
goto error;
if (!push_val(ip))
return (0);
break;
case '(':
if (vflag == 1)
goto error;
if (!push_op('('))
return (0);
level++;
(*ip)++;
break;
case ')':
if (vflag == 0)
goto error;
if (level == 0)
goto error;
while (op_stack[op_idx] != '(') {
if (!do_op())
return (0);
}
op_idx--;
level--;
(*ip)++;
break;
case '>':
case '<':
if (vflag == 0)
goto error;
if (prlnbuf[++(*ip)] != c)
goto error;
if (!push_op(c))
return (0);
(*ip)++;
break;
case '~':
if (vflag == 1)
goto error;
if (!push_op(c))
return (0);
(*ip)++;
break;
case '-':
if (vflag == 0)
c = '_';
if (!push_op(c))
return (0);
(*ip)++;
break;
case '%':
case '*':
case '&':
if (vflag == 0) {
if (!push_val(ip))
return (0);
break;
}
case '+':
case '/':
case '^':
case '|':
if (vflag == 0)
goto error;
if (!push_op(c))
return (0);
(*ip)++;
break;
case ' ':
case '\t':
(*ip)++;
break;
case ';':
case '\0':
end = 1;
break;
case ',':
end = 2;
break;
default:
end = 3;
break;
}
}
}
if (vflag == 0)
goto error;
if (level != 0)
goto error;
while (op_stack[op_idx] != '') {
if (!do_op())
return (0);
}
value = val_stack[val_idx];
if (undef != 0) {
if (pass == LAST_PASS) {
error("Undefined symbol in operand field!");
/* return (0); */
}
value = 0;
}
switch (flag) {
case ';':
if (end != 1)
goto error;
(*ip)++;
break;
case ',':
if (end != 2)
goto error;
(*ip)++;
break;
}
return (1);
error:
error("Syntax error in expression!");
return(0);
}
/* get a number and push it on the value stack */
push_val(int *ip)
{
int mul;
int val;
char c;
val = 0;
c = prlnbuf[*ip];
if (c == '*') {
val = (loccnt + (page << 13));
(*ip)++;
}
else if (c == '\'') {
(*ip)++;
val = prlnbuf[(*ip)++];
if ((prlnbuf[(*ip)++] != c) || (val == 0)) {
error("Syntax Error!");
return (0);
}
}
else if (isalpha(c) || c == '_' || c == '.') {
colsym(ip);
if (c = check_keyword()) {
if (!push_op(c))
return (0);
else
return (1);
}
if ((vlablptr = stlook()) == NULL)
undef = 1;
else if (vlablptr->type == UNDEF)
undef = 1;
else
val = vlablptr->value;
vcount++;
}
else {
if (c == '$')
mul = 16;
else if (c == '&')
mul = 8;
else if (c == '%')
mul = 2;
else if (c >= '0' && c <= '9') {
mul = 10;
val = c - '0';
}
for (;;) {
c = prlnbuf[++(*ip)];
if (isdigit(c))
c -= '0';
else if (isalpha(c)) {
c = tolower(c);
if (c >= 'a' && c <= 'f') {
c -= 'a';
c += 10;
}
else
break;
}
else if (c == '_' && mul == 2)
continue;
else
break;
if (c >= mul)
break;
val = (val * mul) + c;
}
}
if (val_idx == 63) {
error("Expression too complex!");
return (0);
}
val_idx++;
val_stack[val_idx] = val;
vflag = 1;
return(1);
}
/* verify a keyword */
char check_keyword(void)
{
char c = 0;
if (!strnicmp(symbol, keyword[0], 5))
c = 'h';
else if (!strnicmp(symbol, keyword[1], 4))
c = 'l';
else if (!strnicmp(symbol, keyword[2], 5))
c = 'p';
else if (!strnicmp(symbol, keyword[3], 5))
c = 'b';
if (c == 'p' || c == 'b') {
vlablptr = NULL;
vcount = 0;
}
return (c);
}
/* push an operator on the stack */
push_op(char op)
{
if (op != '(') {
while (op_pri(op_stack[op_idx]) >= op_pri(op)) {
if (!do_op())
return (0);
}
}
if (op_idx == 63) {
error("Expression too complex!");
return (0);
}
op_idx++;
op_stack[op_idx] = op;
vflag = 0;
return (1);
}
/* return the priority of an operator */
op_pri(char op)
{
int pri = 0;
switch (op) {
case 'b':
case 'h':
case 'l':
case 'p':
case '_':
case '~':
pri++;
pri++;
case '*':
case '/':
case '%':
pri++;
case '+':
case '-':
pri++;
case '<':
case '>':
pri++;
pri++;
pri++;
case '&':
pri++;
case '^':
pri++;
case '|':
pri++;
case '':
case '(':
break;
}
return (pri);
}
/* apply an operator to the value stack */
do_op(void)
{
unsigned long val[2];
char op;
op = op_stack[op_idx--];
val[0] = val_stack[val_idx];
if (op_pri(op) < 10)
val[1] = val_stack[--val_idx];
switch (op) {
case 'p':
if (vcount != 1) {
if (vcount == 0)
error("No symbol in function PAGE!");
else
error("Too many symbols in function PAGE!");
return (0);
}
if (vlablptr)
val[0] = vlablptr->page;
break;
case 'b':
if (vcount != 1) {
if (vcount == 0)
error("No symbol in function BANK!");
else
error("Too many symbols in function BANK!");
return (0);
}
if (vlablptr)
val[0] = vlablptr->bank;
break;
case 'h':
val[0] = (val[0] & 0xFF00) >> 8;
break;
case 'l':
val[0] = val[0] & 0xFF;
break;
case '+':
val[0] = val[1] + val[0];
break;
case '-':
val[0] = val[1] - val[0];
break;
case '*':
val[0] = val[1] * val[0];
break;
case '/':
if (val[0] == 0) {
error("Divide by zero!");
return (0);
}
val[0] = val[1] / val[0];
break;
case '%':
if (val[0] == 0) {
error("Divide by zero!");
return (0);
}
val[0] = val[1] % val[0];
break;
case '_':
val[0] = -val[0];
break;
case '<':
val[0] = val[1] << (val[0] & 0x1F);
break;
case '>':
val[0] = val[1] >> (val[0] & 0x1f);
break;
case '|':
val[0] = val[1] | val[0];
break;
case '^':
val[0] = val[1] ^ val[0];
break;
case '&':
val[0] = val[1] & val[0];
break;
case '~':
val[0] = ~val[0];
break;
default:
error("Invalid operator in expression!");
return (0);
}
val_stack[val_idx] = val[0];
return (1);
}